package com.chat.handler;

import com.alibaba.fastjson.JSONObject;
import com.netty.imp.IMMessage;
import com.netty.imp.IMP;
import com.netty.imp.IMPDecoder;
import com.netty.imp.IMPEncoder;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.apache.commons.lang3.StringUtils;

import java.util.Objects;


/**
 * @author kewei
 * 主要处理用户登陆、退出、上线、下线、发送消息等行为动作的逻辑
 */
public class MsgProcessor {

    /**
     * 记录在线用户数量
     */
    private static ChannelGroup onlineUsers = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 定义一些扩展属性
     */
    private static final AttributeKey<String> NICK_NAME = AttributeKey.valueOf("nickName");
    private static final AttributeKey<String> IP_ADDR = AttributeKey.valueOf("ipAddr");
    private static final AttributeKey<JSONObject> ATTRS = AttributeKey.valueOf("attrs");
    private static final AttributeKey<String> FROM = AttributeKey.valueOf("from");

    /**
     * 解码器
     */
    private IMPDecoder decoder = new IMPDecoder();

    /**
     * 编码器
     */
    private IMPEncoder encoder = new IMPEncoder();

    /**
     * 获取用户的昵称
     *
     * @param client
     * @return
     */
    public String getNickName(Channel client) {
        return client.attr(NICK_NAME).get();
    }

    /**
     * 获取用户远程IP地址
     *
     * @param client
     * @return
     */
    public String getAddress(Channel client) {
        return client.remoteAddress().toString().replace("/", "");
    }

    /**
     * 获取用户的扩展属性
     *
     * @param client
     * @return
     */
    public JSONObject getAttrs(Channel client) {
        return client.attr(ATTRS).get();
    }

    /**
     * 设置用户的扩展属性
     *
     * @param client
     * @param key
     * @param value
     */
    public void setAttrs(Channel client, String key, Object value) {
        JSONObject oldObject = client.attr(ATTRS).get();
        JSONObject newObject = (JSONObject) oldObject.clone();
        newObject.put(key, value);
        //采用CAS方式进行处理
        if (client.attr(ATTRS).compareAndSet(oldObject, newObject)) {
            return;
        } else {
            setAttrs(client, key, value);
        }
    }

    /**
     * 退出操作
     *
     * @param client
     */
    public void logOut(Channel client) {
        //如果昵称为空，表示非法登陆
        if (StringUtils.isBlank(getNickName(client))) {
            return;
        }
        for (Channel channel : onlineUsers) {
            IMMessage request = new IMMessage(IMP.SYSTEM.name(), System.currentTimeMillis(), onlineUsers.size(), String.format("%s离开", getNickName(client)));
            channel.writeAndFlush(new TextWebSocketFrame(encoder.encode(request)));
        }
        onlineUsers.remove(client);
    }

    /**
     * 发送消息
     *
     * @param client
     * @param msg
     */
    public void sendMsg(Channel client, IMMessage msg) {
        sendMsg(client, encoder.encode(msg));
    }

    /**
     * 发送消息
     *
     * @param client
     * @param msg
     */
    public void sendMsg(Channel client, String msg) {
        IMMessage request = decoder.decode(msg);
        if (Objects.isNull(request)) {
            return;
        }
        String addr = getAddress(client);
        //登陆
        if (IMP.LOGIN.name().equals(request.getCmd())) {
            client.attr(NICK_NAME).getAndSet(request.getSender());
            client.attr(IP_ADDR).getAndSet(addr);
            client.attr(FROM).getAndSet(request.getTerminal());
            onlineUsers.add(client);
            for (Channel channel : onlineUsers) {
                boolean isSelf = channel == client;
                if (!isSelf) {
                    request = new IMMessage(IMP.SYSTEM.name(), System.currentTimeMillis(), onlineUsers.size(), getNickName(client) + "加入");
                } else {
                    request = new IMMessage(IMP.SYSTEM.name(), System.currentTimeMillis(), onlineUsers.size(), "已经与服务器建立连接!");
                }
                if ("Console".equals(channel.attr(FROM).get())) {
                    channel.writeAndFlush(request);
                    continue;
                }
                String content = encoder.encode(request);
                channel.writeAndFlush(new TextWebSocketFrame(content));
            }
        }
        //聊天
        else if (IMP.CHAT.name().equals(request.getCmd())) {
            for (Channel channel : onlineUsers) {
                boolean isSelf = channel == client;
                if (isSelf) {
                    request.setSender("you");
                } else {
                    request.setSender(getNickName(client));
                }
                request.setTime(System.currentTimeMillis());
                if ("Console".equals(channel.attr(FROM).get()) && !isSelf) {
                    channel.writeAndFlush(request);
                    continue;
                }
                String content = encoder.encode(request);
                channel.writeAndFlush(new TextWebSocketFrame(content));
            }
        }
        //鲜花
        else if (IMP.FLOWER.name().equals(request.getCmd())) {
            JSONObject attrs = getAttrs(client);
            long currentTime = System.currentTimeMillis();
            if (!Objects.isNull(attrs)) {
                long lastTime = attrs.getLongValue("lastFlowerTime");
                //10秒内不允许重送鲜花
                int seconds = 10;
                long sub = currentTime - lastTime;
                if (sub < 1000 * seconds) {
                    request.setSender("you");
                    request.setCmd(IMP.SYSTEM.name());
                    request.setContent("您送鲜花太频繁," + (seconds - Math.round(sub / 1000)) + "秒后再试");
                    String content = encoder.encode(request);
                    client.writeAndFlush(new TextWebSocketFrame(content));
                    return;
                }
            }
            //正常送花
            for (Channel channel : onlineUsers) {
                if (channel == client) {
                    request.setSender("you");
                    request.setContent("您给大家送了一波鲜花雨");
                    setAttrs(client, "lastFlowerTime", currentTime);
                } else {
                    request.setSender(getNickName(client));
                    request.setContent(getNickName(client) + "给大家送了一波鲜花雨!");
                }
                request.setTime(System.currentTimeMillis());
                String content = encoder.encode(request);
                channel.writeAndFlush(new TextWebSocketFrame(content));
            }
        }
    }
}
